package ca.etsmtl.log730.projet2.documents;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.concurrent.Semaphore;

import ca.etsmtl.log730.projet2.users.User;
import ca.etsmtl.log730.projet2.users.UserListener;

public class DocumentController implements UserListener {

	private Map<UUID, Document> documentMap = new HashMap<UUID, Document>();
	
	public List<DocumentListener> documentListeners = new ArrayList<DocumentListener>();
	
	public void addDocumentListener(DocumentListener dl) {
		this.documentListeners.add(dl);
	}
	
	public void removeDocumentListener(DocumentListener dl) {
		this.documentListeners.remove(dl);
	}
	
	
	public void setNewValues(UUID d, Document doc, User u) {
		if(documentMap.get(d).getAccess().getEditors().contains(u)) {
			documentMap.put(d, doc);
			fireDocumentChanged(d, doc);
		}
	}
	
	public Document getDocument(UUID d, User u) {
		if(documentMap.get(d).getAccess().getViewers().contains(u)
				||
				documentMap.get(d).getAccess().getEditors().contains(u)) {
			Document sel = documentMap.get(d);
			Document doc = new Document("");

			doc.getData().append(sel.getData());
			doc.getAccess().getViewers().addAll(sel.getAccess().getViewers());
			doc.getAccess().getEditors().addAll(sel.getAccess().getEditors());
			
			return doc;
		}
		return null;
	}
	
	private Semaphore semaphore = new Semaphore(1);
	/*
	 * User permissions managements
	 */
	public void addViewer(UUID d, User u) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		documentMap.get(d).getAccess().getEditors().remove(u);
		documentMap.get(d).getAccess().getViewers().add(u);
		
		semaphore.release();
		
	}
	
	public void addEditor(UUID d, User u) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		documentMap.get(d).getAccess().getViewers().remove(u);
		documentMap.get(d).getAccess().getEditors().add(u);
		semaphore.release();
	}
	
	
	public void removeViewer(UUID d, User u) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		documentMap.get(d).getAccess().getViewers().remove(u);
		semaphore.release();
	}
	
	public void removeEditor(UUID d, User u) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		documentMap.get(d).getAccess().getEditors().remove(u);
		semaphore.release();
	}
	
	
	public void fireDocumentChanged(UUID id, Document doc) {
		for(DocumentListener dl: documentListeners) {
			dl.documentChanged(id, doc);
		}
		
	}
	public void fireDocumentAdded(UUID id, Document doc) {
		for(DocumentListener dl: documentListeners) {
			dl.documentAdded(id, doc);
		}
	}
	
	public void fireDocumentRemoved(UUID id, Document doc) {
		for(DocumentListener dl: documentListeners) {
			dl.documentRemoved(id, doc);
		}
	}

	@Override
	public void userJoined(User u) {
	}

	@Override
	public void userQuitted(User u) {
		try {
			semaphore.acquire();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		for(Entry<UUID, Document> e: documentMap.entrySet()) {
			if(e.getValue().getAccess().getEditors().contains(u)) {
				this.removeEditor(e.getKey(), u);
			} else if(e.getValue().getAccess().getViewers().contains(u)) {
				this.removeViewer(e.getKey(), u);
			}
		}
		semaphore.release();
	}
}
